# -*- coding: UTF-8 -*-
'''
@Project ：automation_-interface_testing
@File    ：requests_client.py
@IDE     ：PyCharm 
@Author  ：思亦忆
@Date    ：2025/9/5 星期五 21:57:34

'''
"""
HTTP请求封装 - 支持多种请求方式和参数，集成配置文件读取
"""
import requests
from typing import Dict, Any, Optional, Union
from pathlib import Path
from src.common.logs import get_logger
from src.common.config_loader import ConfigManager


class RequestClient:
    """
    HTTP请求客户端封装类
    支持从配置文件读取基础URL、超时时间、请求头等配置
    """
    
    def __init__(self, base_url: str = None, config: ConfigManager = None, 
                 timeout: int = 30, environment: str = 'test'):
        """
        初始化请求客户端
        
        Args:
            base_url: 基础URL，如果为None则从配置文件读取
            config: ConfigManager实例，如果为None则自动创建
            timeout: 请求超时时间（秒），默认30秒
            environment: 环境名称，默认'test'
        """
        self.logger = get_logger(module_name='request_client')
        self.session = requests.Session()
        self.timeout = timeout
        self.environment = environment
        
        # 加载配置
        self.config = config or ConfigManager(environment=environment)
        self._load_config()
        
        # 设置base_url（优先使用传入的参数，其次从配置读取）
        if base_url:
            self.base_url = base_url.rstrip('/')
        else:
            self.base_url = self._get_base_url_from_config()
        
        # 设置默认请求头
        self._setup_default_headers()
        
        self.logger.info(f"RequestClient初始化完成，base_url: {self.base_url}, timeout: {self.timeout}")

    def _load_config(self):
        """从配置文件加载请求相关配置"""
        try:
            # 从配置中读取超时时间
            api_config = self.config.get_api_config()
            if api_config and 'timeout' in api_config:
                self.timeout = api_config.get('timeout', self.timeout)
            
            # 从配置中读取其他HTTP配置
            if api_config:
                self.verify_ssl = api_config.get('verify_ssl', True)
                self.max_retries = api_config.get('max_retries', 0)
            else:
                self.verify_ssl = True
                self.max_retries = 0
                
        except Exception as e:
            self.logger.warning(f"加载配置时出错，使用默认值: {e}")
            self.verify_ssl = True
            self.max_retries = 0

    def _get_base_url_from_config(self) -> Optional[str]:
        """从配置文件获取base_url"""
        try:
            # 优先从environment配置中读取api_url
            env_config = self.config.config.get('environment', {})
            if env_config and 'api_url' in env_config:
                api_url = env_config.get('api_url')
                # 如果api_url不包含协议，添加http://
                if api_url and not api_url.startswith(('http://', 'https://')):
                    api_url = f"http://{api_url}"
                return api_url.rstrip('/')
            
            # 其次从test_url读取
            test_url = self.config.config.get('test_url')
            if test_url:
                return test_url.rstrip('/')
            
            # 最后尝试从website配置读取
            website_config = self.config.get_website_config()
            if website_config and 'base_url' in website_config:
                return website_config.get('base_url').rstrip('/')
                
        except Exception as e:
            self.logger.warning(f"从配置读取base_url失败: {e}")
        
        return None

    def _setup_default_headers(self):
        """设置默认请求头"""
        default_headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
            'Content-Type': 'application/json'
        }
        
        # 从配置中读取自定义请求头
        try:
            api_config = self.config.get_api_config()
            if api_config and 'headers' in api_config:
                custom_headers = api_config.get('headers', {})
                default_headers.update(custom_headers)
        except Exception as e:
            self.logger.debug(f"读取自定义请求头失败: {e}")
        
        self.session.headers.update(default_headers)

    def request(self, method: str, endpoint: str, timeout: int = None, 
                **kwargs) -> requests.Response:
        """
        发送HTTP请求
        
        Args:
            method: HTTP方法 (GET, POST, PUT, DELETE等)
            endpoint: 接口端点
            timeout: 超时时间（秒），如果为None则使用默认值
            **kwargs: 其他requests参数
            
        Returns:
            requests.Response对象
        """
        # 构建完整URL
        if self.base_url:
            url = f"{self.base_url}{endpoint}" if endpoint.startswith('/') else f"{self.base_url}/{endpoint}"
        else:
            url = endpoint
        
        # 使用传入的timeout或默认值
        request_timeout = timeout or self.timeout
        
        # 设置SSL验证
        if 'verify' not in kwargs:
            kwargs['verify'] = self.verify_ssl
        
        self.logger.info(f"发送请求: {method.upper()} {url}")
        self.logger.debug(f"请求参数: {kwargs}")
        self.logger.debug(f"超时设置: {request_timeout}秒")

        try:
            response = self.session.request(
                method, 
                url, 
                timeout=request_timeout,
                **kwargs
            )
            
            self.logger.info(f"响应状态码: {response.status_code}")
            
            # 记录响应内容（限制长度避免日志过大）
            response_text = response.text
            if len(response_text) > 1000:
                self.logger.debug(f"响应内容（前1000字符）: {response_text[:1000]}...")
            else:
                self.logger.debug(f"响应内容: {response_text}")

            return response

        except requests.exceptions.Timeout as e:
            self.logger.error(f"请求超时: {url}, 超时时间: {request_timeout}秒")
            raise
        except requests.exceptions.ConnectionError as e:
            self.logger.error(f"连接错误: {url}, 错误信息: {e}")
            raise
        except requests.exceptions.RequestException as e:
            self.logger.error(f"请求失败: {url}, 错误信息: {e}")
            raise

    def get(self, endpoint: str, params: Dict = None, timeout: int = None, **kwargs):
        """
        GET请求
        
        Args:
            endpoint: 接口端点
            params: URL参数
            timeout: 超时时间（秒）
            **kwargs: 其他requests参数
            
        Returns:
            requests.Response对象
        """
        return self.request('GET', endpoint, params=params, timeout=timeout, **kwargs)

    def post(self, endpoint: str, data: Any = None, json: Any = None, 
             timeout: int = None, **kwargs):
        """
        POST请求
        
        Args:
            endpoint: 接口端点
            data: 表单数据
            json: JSON数据
            timeout: 超时时间（秒）
            **kwargs: 其他requests参数
            
        Returns:
            requests.Response对象
        """
        return self.request('POST', endpoint, data=data, json=json, timeout=timeout, **kwargs)

    def put(self, endpoint: str, data: Any = None, json: Any = None, 
            timeout: int = None, **kwargs):
        """
        PUT请求
        
        Args:
            endpoint: 接口端点
            data: 表单数据
            json: JSON数据
            timeout: 超时时间（秒）
            **kwargs: 其他requests参数
            
        Returns:
            requests.Response对象
        """
        return self.request('PUT', endpoint, data=data, json=json, timeout=timeout, **kwargs)

    def delete(self, endpoint: str, timeout: int = None, **kwargs):
        """
        DELETE请求
        
        Args:
            endpoint: 接口端点
            timeout: 超时时间（秒）
            **kwargs: 其他requests参数
            
        Returns:
            requests.Response对象
        """
        return self.request('DELETE', endpoint, timeout=timeout, **kwargs)

    def patch(self, endpoint: str, data: Any = None, json: Any = None, 
              timeout: int = None, **kwargs):
        """
        PATCH请求
        
        Args:
            endpoint: 接口端点
            data: 表单数据
            json: JSON数据
            timeout: 超时时间（秒）
            **kwargs: 其他requests参数
            
        Returns:
            requests.Response对象
        """
        return self.request('PATCH', endpoint, data=data, json=json, timeout=timeout, **kwargs)

    def set_header(self, key: str, value: str):
        """
        设置请求头
        
        Args:
            key: 请求头键名
            value: 请求头值
        """
        self.session.headers[key] = value
        self.logger.debug(f"设置请求头: {key} = {value}")

    def set_headers(self, headers: Dict[str, str]):
        """
        批量设置请求头
        
        Args:
            headers: 请求头字典
        """
        self.session.headers.update(headers)
        self.logger.debug(f"批量设置请求头: {headers}")

    def set_auth_token(self, token: str, token_type: str = 'Bearer'):
        """
        设置认证token
        
        Args:
            token: token值
            token_type: token类型，默认为'Bearer'
        """
        auth_header = f'{token_type} {token}' if token_type else token
        self.set_header('Authorization', auth_header)
        self.logger.info("认证token已设置")

    def login(self, username: str = None, password: str = None, 
              login_endpoint: str = '/login', account_type: str = None):
        """
        登录方法
        
        Args:
            username: 用户名，如果为None则从配置读取
            password: 密码，如果为None则从配置读取
            login_endpoint: 登录接口端点
            account_type: 账号类型，用于从配置读取账号信息
            
        Returns:
            requests.Response对象
        """
        # 如果未提供用户名密码，尝试从配置读取
        if not username or not password:
            if account_type:
                account_config = self.config.get_account_config(account_type)
                username = username or account_config.get('username')
                password = password or account_config.get('password')
            else:
                # 尝试从user配置读取（兼容现有配置格式）
                user_config = self.config.config.get('user', {})
                if user_config:
                    # 取第一个用户配置
                    first_user = list(user_config.values())[0] if user_config else {}
                    username = username or first_user.get('username')
                    password = password or first_user.get('password')
        
        if not username or not password:
            raise ValueError("用户名和密码不能为空，请提供参数或配置账号信息")
        
        login_data = {
            'username': username,
            'password': password
        }

        self.logger.info(f"开始登录，用户名: {username}")
        response = self.post(login_endpoint, json=login_data)

        if response.status_code == 200:
            try:
                response_data = response.json()
                # 尝试多种方式获取token
                token = None
                if 'data' in response_data and 'token' in response_data['data']:
                    token = response_data['data']['token']
                elif 'token' in response_data:
                    token = response_data['token']
                elif 'access_token' in response_data:
                    token = response_data['access_token']
                
                if token:
                    self.set_auth_token(token)
                    self.logger.info("登录成功，token已保存")
                else:
                    self.logger.warning("登录成功但未找到token")
            except Exception as e:
                self.logger.warning(f"解析登录响应失败: {e}")
        else:
            self.logger.error(f"登录失败，状态码: {response.status_code}")
        
        return response

    def close(self):
        """关闭session"""
        self.session.close()
        self.logger.info("RequestClient session已关闭")

    def __enter__(self):
        """上下文管理器入口"""
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """上下文管理器出口"""
        self.close()